#pragma once

#include <angelscript.h>
#include <boost/unordered_map.hpp>
#include <boostext/util/make_shared.hpp>
#include <engine.core/noncopyable.hpp>

#include "exports.hpp"
#include "Reflectable.hpp"
#include "Type.hpp"




namespace Engine
{
	namespace Script
	{
		class ENGINE_SCRIPT_API Module
			: public Reflectable
			, public noncopyable
		{
		public:

			SHARED(Module);

		protected:

			Module(asIScriptModule* module);
			virtual void post_create(ptr _this);

		public:

			MAKE_SHARED1(Module, asIScriptModule*);
			virtual ~Module();



			/**
			 * @returns the bytecode of this module
			 */
			std::vector<char> bytecode() const;



			/**
			 * @returns the function id of the function with the given declaration
			 * @throws  boostext::invalid_value_exception in case there is no such function
			 */
			int functionIdByDecl(const char* decl) const;



			/**
			 * @returns the number of types
			 */
			virtual int typeCount() const;

			/**
			 * @tests if there is a type with the given id
			 */
			virtual bool hasType(int id) const;

			/**
			 * @returns the type with the given id
			 * @throws when there is no type with the given id
			 */
			virtual const Type& type(int id) const;

			/**
			 * @returns the function with the given id
			 * @throws when there is no function with the given id
			 */
			virtual Function function(int id) const;

			/**
			 * @returns all object types
			 */
			virtual std::vector<Type> types() const;

		protected:

			/**
			 * Reflects over this module.
			 * This function is only called in the constructor.
			 */
			void reflect();

		private:

			typedef boost::unordered_map<int, Type>   TypeMap;

			weak_ptr           m_this;
			asIScriptModule*   m_module;
			TypeMap            m_types;
		};
		///////////////////////////////////////////////////////////////////////////////////////////
	}
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
